#include "axbopenglwidget.h"
#include <QtDebug>
// 创建 VBO VAO 对象， 并赋予 ID
unsigned int VBO, VAO, EBO;

// 去除重复的点
float vertices[] = {
    // first triangle
    0.5f, 0.5f, 0.0f, // top right
    0.5f, -0.5f, 0.0f, // bottom right
    -0.5f, -0.5f, 0.0f, // bottom left
    -0.5f, 0.5f, 0.0f // top left
};
// 添加 怎么画的 索引
unsigned int indices[] = {
    // note that we start from 0!
    0, 1, 3, // 第一个三角形
    1, 2, 3 // 第二个三角形
};

unsigned int shaderProgram;

const char *vertexShaderSource = "#version 330 core\n" \
        "layout (location = 0) in vec3 aPos;\n" \
        "void main() {\n" \
        "gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); \n" \
        "}\0";

const char* fragmentShaderSource = "#version 330 core\n" \
        "out vec4 FragColor;\n" \
        "void main() {\n" \
        " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" \
        "}\n\0";


AXBOpenGLWidget::AXBOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{

}

void AXBOpenGLWidget::initializeGL()
{
    // 初始化 opengl 中的函数指针
    initializeOpenGLFunctions();


    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    // 绑定 VBO 和 VAO 对象
    glBindVertexArray(VAO); // 告诉 VAO 小助理，现在开始记了
    glBindBuffer(GL_ARRAY_BUFFER, VBO); // VBO 也是一样的

    // 为当前绑定到 target 的缓冲区对象创建一个新的数据存储.（是在显存中分配缓冲）
    // 如果 data 不是 NULL, 则使用 来自此指针的数据 初始化数据存储
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 告知 显卡如何解析缓冲里的属性值 , 让 VAO 小助理，记录 如何解析缓冲中的内容
    // 第 0 个属性， 里面有三个值(x,y,z), 每个值是一个 Float类型，不需要标准化，步长为三个float 大小了， 偏移为0
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);

    // 开启 VAO 管理的第一个属性
    glEnableVertexAttribArray(0);




    // 顶点着色器
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER); // 创建一个顶点着色器
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); // 顶点着色器和 对应的源码，进行绑定
    glCompileShader(vertexShader); // 编译顶点着色器
    // 检查编译是否成功
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED  -- " << infoLog << "\n";
    }


    // 片源 着色器/ 片段着色器
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader); // 编译顶点着色器
    // 检查编译是否成功
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success) {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED  -- " << infoLog << "\n";
    }


    //链接 着色器
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader); // 将顶点着色器加入 program中
    glAttachShader(shaderProgram, fragmentShader); // 将 片源着色器加入 program 中
    glLinkProgram(shaderProgram); // 链接编译
    // check for linking errors
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 默认是用 GL_FILL 填充 ，使用 GL_LINE 用线条进行填充。


    glGenBuffers(1, &EBO); // 创建 EBO buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 传输数据

    // 这里 EBO 中的信息，也被 VAO 小助理偷偷记录了下来

//    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 解绑 EBO
    // VAO VBO 两个助理记录完，这些信息，后让其休息 （解绑）
    glBindBuffer(GL_ARRAY_BUFFER, 0); // 解绑 VBO
    glBindVertexArray(0); // 解绑 VAO



    // VAO 都记录那些东西
    /**
    * 1. 目标是 GL_ELEMENT_ARRAY_BUFFER (EBO/IBO 索引缓冲) 的 glBindBuffer 函数调用，会被 VAO 记录下来
    * 2. 目标是 GL_ARRAY_BUFFER (VBO) 的 glBindBuffer 函数调用， VAO 不做记录。
    */
}

void AXBOpenGLWidget::resizeGL(int w, int h)
{
    Q_UNUSED(w);
    Q_UNUSED(h);
//    glViewport(0, 0, w, h);
}

void AXBOpenGLWidget::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 设置清理时的颜色
    glClear(GL_COLOR_BUFFER_BIT); // 使用

    glUseProgram(shaderProgram);
    // 此时要画图了， VAO 小助理，你要再次被用
    glBindVertexArray(VAO);
//    glDrawArrays(GL_TRIANGLES, 0, 6); // 画一个矩形 ， 这里原先是从 VBO 数组中那点的坐标的
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 /*&indices*/); // 现在是从 EBO(索引表) 中那 6 个索引， 每个索引的类型是int , 去画 三角形

}
